﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace Daco.Web.Store
{
    public struct CUnitMeasure
    {
        public string Code;
        public string Name;

        public CUnitMeasure(string code, string name)
        {
            this.Code = code;
            this.Name = name;
        }
    }

    public struct CProductDescription
    {
        public int DescriptionID;
        public string Title;
        public string Body;

        public CProductDescription(int descriptionID, string title, string body)
        {
            this.DescriptionID = descriptionID;
            this.Title = title;
            this.Body = body;
        }
        public CProductDescription(int descriptionID, string title)
            : this(descriptionID, title, string.Empty)
        {
        }
    }

    public class CProduct
    {
        /// <summary>
        /// get the productID
        /// </summary>
        public string ProductID { get; protected set; }
        /// <summary>
        /// get the addedDate
        /// </summary>
        public DateTime AddedDate { get; private set; }
        /// <summary>
        /// get or set product's series
        /// </summary>
        public string Series { get; set; }
        /// <summary>
        /// get or set product's name
        /// </summary>
        public string ProductName { get; set; }
        /// <summary>
        /// get product's encoded-name
        /// </summary>
        public string EncodedProductName
        {
            get
            {
                return System.Web.HttpContext.Current.Server.UrlEncode(Daco.Utils.CHelper.LatinToAscii(this.ProductName));
            }
        }
        /// <summary>
        /// get or set product's price
        /// </summary>
        public float UnitPrice { get; set; }
        /// <summary>
        /// get or set Unitmeasure
        /// </summary>
        public CUnitMeasure UnitMeasure;
        /// <summary>
        /// get or set currency
        /// </summary>
        public string Currency { get; set; }
        /// <summary>
        /// get or set Units in stock
        /// </summary>
        public int UnitsInStock { get; set; }
        /// <summary>
        /// get or set EnablePriceConfidential
        /// </summary>
        public bool EnablePriceConfidential { get; set; }
        /// <summary>
        /// get or set enable shopping
        /// </summary>
        public bool EnableShopping { get; set; }
        /// <summary>
        /// get total rating
        /// </summary>
        public int TotalRating { get; protected set; }
        /// <summary>
        /// get total vote
        /// </summary>
        public int VoteCount { get; protected set; }
        public CManufacture Manufacture;
        public CProductCategory ProductCategory { get; protected set; }
        public double AverageRating
        {
            get
            {
                if (VoteCount > 0)
                    return ((double)this.TotalRating / (double)this.VoteCount);
                else
                    return 0.0;
            }
        }
        private CTypeCollection<CProductReview> _productReviews;
        public CTypeCollection<CProductReview> ProductReviews
        {
            get
            {
                if (_productReviews == null)
                    _productReviews = GetProductReviews(this.ProductID);
                return _productReviews;
            }
        }
        private List<CPhoto> _productPhotos;
        public List<CPhoto> ProductPhotos
        {
            get
            {
                if (_productPhotos == null)
                    _productPhotos = CPhoto.GetPhotos(this.ProductID);
                return _productPhotos;
            }
        }

        #region Constructors
        public CProduct()
        {
            this.ProductID = CProduct.NewProductID();
            this.AddedDate = DateTime.Now;
            this.UnitsInStock = 0;
            this.UnitPrice = 0;
        }

        public CProduct(string productID)
        {
            this.ProductID = productID;
        }
        public CProduct(string productSeries, float unitPrice, string measureCode, string currency, int unitsInStock)
            : this()
        {
            this.AddedDate = DateTime.Now;
            this.Series = productSeries;
            this.UnitPrice = unitPrice;
            this.UnitMeasure.Code = measureCode;
            this.Currency = currency;
            this.UnitsInStock = unitsInStock;
        }
        public CProduct(string productID, DateTime addedDate, string productSeries, string productName, float unitPrice, string measureCode, string unitMeasure, string currency, int unitsInStock, int totalRating, int voteCount)
            : this(productSeries, unitPrice, measureCode, currency, unitsInStock)
        {
            this.ProductID = productID;
            this.AddedDate = addedDate;
            this.UnitMeasure.Name = unitMeasure;
            this.ProductName = productName;
            this.TotalRating = totalRating;
            this.VoteCount = voteCount;
        }
        #endregion

        #region Public member methods
        public bool Update()
        {
            bool success = Providers.CStoreProvider.Instance.UpdateProductDetail
                (
                    this.ProductID, this.Manufacture.ManufactureID, this.Manufacture.Name,
                    this.Series, this.UnitPrice, this.Currency, this.UnitMeasure.Code, this.UnitsInStock,
                    this.EnablePriceConfidential, this.EnableShopping
                );

            return success;
        }
        public bool Delete()
        {
            return false;
        }

        public void IncrementViewCount()
        {
            Providers.CStoreProvider.Instance.IncrementViewCount(this.ProductID);
        }
        public CPhoto GetDefaulPhoto()
        {
            if (this.ProductPhotos.Count > 0)
            {
                CPhoto photo = this.ProductPhotos.Find(delegate(CPhoto match)
                {
                    return match.Primary == true;
                });

                if (photo == null) photo = this.ProductPhotos[0];
                return photo;
            }
            else
                return new CPhoto();
        }
        public void RefCategory(CProductCategory category)
        {
            this.ProductCategory = category;
        }
        public bool UpdateProductDescription()
        {
            bool success = false;
            return success;
            //return Providers.CStoreProvider.Instance.UpdateProductDescription(this.ProductCategory.CategoryID, this.ProductCategory.Title, this.ProductID, this.ProductName, this.Description);
        }
        public CProductDescription GetDescription(int descriptionID)
        {
            DataRow row = Providers.CStoreProvider.Instance.GetProductDescription(descriptionID);

            return row == null ? new CProductDescription(-1, string.Empty) : new CProductDescription((int)row["ProductDescriptionID"], row["Title"].ToString(), row["Body"].ToString());
        }
        public bool AddDescription(string title, string description)
        {
            bool success = false;

            if ((success = Providers.CStoreProvider.Instance.AddProductDescription(this.ProductID, title, description)))
            {
            }

            return success;
        }
        public List<CProductDescription> GetDescriptions()
        {
            DataTable tblProductDescription = Providers.CStoreProvider.Instance.GetProductDescriptions(this.ProductID);
            List<CProductDescription> descriptions = new List<CProductDescription>();

            foreach (DataRow row in tblProductDescription.Rows)
                descriptions.Add(new CProductDescription((int)row["ProductDescriptionID"], row["Title"].ToString()));

            return descriptions;
        }
        #endregion

        public static List<CManufacture> GetManufactures()
        {
            DataTable tblManufacture = Providers.CStoreProvider.Instance.GetManufactureTable();
            List<CManufacture> manufactures = new List<CManufacture>();

            if (tblManufacture != null && tblManufacture.Rows.Count > 0)
            {
                foreach (DataRow row in tblManufacture.Rows)
                {
                    manufactures.Add(new CManufacture((int)row["ManufactureID"], row["Name"].ToString()));
                }
            }

            return manufactures;
        }

        public static CUnitMeasure[] GetUnitMeasures()
        {
            DataTable tblUnitMeasure = Providers.CStoreProvider.Instance.GetUnitMeasureTable();
            CUnitMeasure[] units = null;
            if (tblUnitMeasure.Rows.Count > 0)
            {
                units = new CUnitMeasure[tblUnitMeasure.Rows.Count];

                for (int i = 0; i < tblUnitMeasure.Rows.Count; i++)
                    units[i] = new CUnitMeasure(tblUnitMeasure.Rows[i]["UnitMeasureCode"].ToString(), tblUnitMeasure.Rows[i]["Name"].ToString());
            }

            return units;
        }

        public static CTree CreateManufactureTree()
        {
            CTree manufactureTree = new CTree();

            DataTable tblManufacture = Providers.CStoreProvider.Instance.GetManufactureTable();
            List<CManufacture> manufactures = new List<CManufacture>();

            if (tblManufacture != null && tblManufacture.Rows.Count > 0)
            {
                foreach (DataRow row in tblManufacture.Rows)
                {
                    //manufactures.Add(new CManufacture((int)row["ManufactureID"], row["Name"].ToString()));
                    manufactureTree.Nodes.AddNode(new CTreeNode(row["Name"].ToString(), row["ManufactureID"].ToString()));
                }
            }

            return manufactureTree;
        }

        public static CTypeCollection<CProductReview> GetProductReviews(string productID)
        {
            return GetProductReviews(productID, true, 1, int.MaxValue);
        }
        public static CTypeCollection<CProductReview> GetProductReviews(string productID, bool approved)
        {
            return GetProductReviews(productID, approved, 1, int.MaxValue);
        }

        public static CTypeCollection<CProductReview> GetProductReviews(string productID, bool approved, int pageIndex, int pageSize)
        {
            int resultCount = 0;
            return
                new CTypeCollection<CProductReview>
                (
                    Providers.CStoreProvider.Instance.GetProductReviews(productID, approved, pageIndex, pageSize, out resultCount),
                    resultCount
                );
        }

        public static int GetProductReviewCount(string productID)
        {
            return GetProductReviewCount(productID, true);
        }
        public static int GetProductReviewCount(string productID, bool approved)
        {
            int resultCount = Providers.CStoreProvider.Instance.GetProductReviewCount(productID, approved);
            return resultCount;
        }

        #region Static Methods
        public static CManufacture GetManufacture(int manufactureID)
        {
            CManufacture manufacture = new CManufacture(-1, string.Empty);

            DataTable tblManufacture = Providers.CStoreProvider.Instance.GetManufacture(manufactureID);
            if (tblManufacture != null && tblManufacture.Rows.Count == 1)
            {
                DataRow row = tblManufacture.Rows[0];

                manufacture.ManufactureID = (int)row["ManufactureID"];
                manufacture.Name = row["Name"].ToString();
                manufacture.Description = row["Description"].ToString();
            }

            return manufacture;
        }
        public static string AddProduct(string productID, string productName, string productSeries, int manufactureID,
            string manufactureName, int pcategoryID, string pcategoryTitle, string unitMeasureCode, float unitPrice, bool enablePriceConfidential, bool enableShopping,
            string currency, int unitsInStock)
        {
            if (Providers.CStoreProvider.Instance.AddProduct(
                DateTime.Now,
                productID,
                productName,
                productSeries,
                manufactureID,
                manufactureName,
                pcategoryID,
                pcategoryTitle,
                unitMeasureCode,
                unitPrice,
                enablePriceConfidential,
                enableShopping,
                currency,
                unitsInStock) == 0)
            {

            }
            else
            {
                productID = string.Empty;
            }

            return productID;
        }
        public static CTypeCollection<CProduct> GetProducts(out int resultCount)
        {
            return GetProducts(1, int.MaxValue, out resultCount);
        }
        public static CTypeCollection<CProduct> GetProducts(int pageIndex, int pageSize, out int resultCount)
        {
            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetProducts(pageIndex, pageSize, out resultCount),
                    resultCount
                );
        }
        public static CTypeCollection<CProduct> GetProducts(int productCategoryID, out int resultCount)
        {
            return GetProducts(productCategoryID, 1, int.MaxValue, out resultCount);
        }
        public static CTypeCollection<CProduct> GetProducts(int productCategoryID, int pageIndex, int pageSize, out int resultCount)
        {
            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetProductsByCategory(productCategoryID, pageIndex, pageSize, out resultCount),
                    resultCount
                );
        }
        //public static CTypeCollection<CProduct> GetProducts(int[] productCategoryIDList, int[] manufactureIDList, string productSeries, string productName, out int resultCount)
        //{
        //    return GetProducts(productCategoryIDList, manufactureIDList, productSeries, productName, 1, int.MaxValue, out resultCount);
        //}
        //public static CTypeCollection<CProduct> GetProducts(int[] productCategoryIDList, int[] manufactureIDList, string productSeries, string productName, int pageIndex, int pageSize, out int resultCount)
        //{
        //    return
        //        new CTypeCollection<CProduct>
        //        (
        //            Providers.CStoreProvider.Instance.GetFilterProducts
        //            (
        //                Daco.Utils.CHelper.ArrayToString<int>(productCategoryIDList, ','),
        //                Daco.Utils.CHelper.ArrayToString<int>(manufactureIDList, ','),
        //                productSeries,
        //                productName,
        //                pageIndex,
        //                pageSize,
        //                out resultCount
        //            ),
        //            resultCount
        //        );

        //}
        public static CTypeCollection<CProduct> GetProducts(object[] productCategoryList, object[] manufactureList, object[] productSeries, string productName, float priceFrom, float priceTo, int pageIndex, int pageSize)
        {
            int resultCount = 0;
            if (priceTo <= priceFrom) priceTo = priceFrom + 10;
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 8) pageSize = 8;

            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetFilterProducts
                    (
                        Daco.Utils.CHelper.ArrayToString<object>(productCategoryList, ','),
                        Daco.Utils.CHelper.ArrayToString<object>(manufactureList, ','),
                        Daco.Utils.CHelper.ArrayToString<object>(productSeries, ','),
                        productName == null ? string.Empty : productName,
                        priceFrom,
                        priceTo,
                        pageIndex,
                        pageSize,
                        out resultCount
                    ),
                    resultCount
                );
        }
        public static CTypeCollection<CProduct> GetNewestProducts(int itemCount)
        {
            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetNewestProducts(itemCount),
                    itemCount
                );
        }

        public static CTypeCollection<CProduct> GetNewestProducts()
        {
            int resultCount = 0;
            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetNewestProductsByCategory(out resultCount),
                    resultCount
                );
        }

        public static CTypeCollection<CProduct> GetFavoriteProducts(int itemCount)
        {
            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetFavoriteProducts(itemCount),
                    itemCount
                );
        }
        public static CTypeCollection<CProduct> GetRelatedProducts(string productID, int categoryID, int manufactureID, int itemCount)
        {
            return
                new CTypeCollection<CProduct>
                (
                    Providers.CStoreProvider.Instance.GetRelatedProducts(productID, categoryID, manufactureID, itemCount),
                    itemCount
                );
        }
        #endregion

        #region Override Methods
        public override bool Equals(object obj)
        {
            CProduct product = (CProduct)obj;
            return product.ProductID == this.ProductID;
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        public override string ToString()
        {
            return base.ToString();
        }
        #endregion

        #region Public static methods
        public static string NewProductID()
        {
            string pid = Guid.NewGuid().GetHashCode().ToString();
            pid = pid.Replace("-", "");

            return string.Format("P-{0}", pid);
        }
        public static bool UpdateProductDescription(string culture, string productID, int productCategoryID, string productCategoryTitle, string productName, string description)
        {
            return Providers.CStoreProvider.Instance.UpdateProductDescription(culture, productCategoryID, productCategoryTitle, productID, productName, description);
        }

        public static CProduct GetProduct(string productID)
        {
            return Providers.CStoreProvider.Instance.GetProduct(productID, false);
        }

        public static CProduct GetProduct(string culture, string productID, bool updateViewCount)
        {
            CProduct product = null;

            product = Providers.CStoreProvider.Instance.GetProduct(productID, updateViewCount);

            return product;
        }

        #endregion
    }

    public class CProductComparer : IComparer<CProduct>
    {
        private Data.ESortBy _sortBy;
        private Data.ESortOrder _sortOrder;

        public CProductComparer(Data.ESortBy sortBy, Data.ESortOrder sortOrder)
        {
            _sortBy = sortBy;
            _sortOrder = sortOrder;
        }

        public bool Equals(CProduct x, CProduct y)
        {
            return x.ProductID == y.ProductID;
        }

        #region IComparer<CProduct> Members

        public int Compare(CProduct x, CProduct y)
        {
            int retv = 0;
            switch (_sortBy)
            {
                case Data.ESortBy.Date:
                    retv = DateTime.Compare(x.AddedDate, y.AddedDate);
                    break;
                case Data.ESortBy.Name:
                    retv = string.Compare(x.ProductName, x.ProductName);
                    break;
                default:
                    retv = x.UnitPrice > y.UnitPrice ? 1 : (x.UnitPrice == y.UnitPrice ? 0 : -1);
                    break;
            }

            return _sortOrder == Data.ESortOrder.ASC ? retv : retv * (-1);
        }

        #endregion
    }

    public class CProductReview
    {
        public int ProductReviewID { get; protected set; }
        public bool IsApproved { get; set; }
        public DateTime ReviewDate { get; protected set; }
        public string PReviewerName { get; set; }
        public string Email { get; set; }
        public string IPAddress { get; protected set; }
        public int Rating { get; set; }
        public string Comments { get; set; }

        public CProductReview(int reviewID, bool isApproved, DateTime reviewDate, string reviewerName
            , string email, string ipAddress, int rating, string comments)
        {
            this.ProductReviewID = reviewID;
            this.IsApproved = IsApproved;
            this.ReviewDate = reviewDate;
            this.PReviewerName = reviewerName;
            this.Email = email;
            this.IPAddress = ipAddress;
            this.Rating = rating;
            this.Comments = comments;
        }
    }
}
